/**============================================================================
 Confidential Information - Limited distribution to authorized persons only.
 This software is protected as an unpublished work under the U.S. Copyright
 Act of 1976.

 Copyright (c) 2011, BluePhoenix Solutions, Inc. All rights reserved.
 ----------------------------------------------------------------------------
 file......: Word.java
 Author....: Vyacheslav Kovalyov
 Created...: 12/27/11

 Description:

 ============================================================================*/
package com.bphx.android.words;

import android.os.Parcel;
import android.os.Parcelable;
import com.bphx.android.exception.BaseException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import static com.bphx.android.WordDroidApplication.getContext;
import static com.bphx.android.exception.ExceptionFactory.getWordCreationException;
import static com.bphx.android.words.WordExceptionType.WORD_INVALID_VARIANTS_ERROR;
import static com.bphx.android.words.WordExceptionType.WORD_VARIANTS_ERROR;
import static java.lang.ClassLoader.getSystemClassLoader;
import static org.apache.commons.lang.StringUtils.EMPTY;
import static org.apache.commons.lang.StringUtils.isNotBlank;

/**
 * @author Vyacheslav Kovalyov
 * @version 1.0
 */
@SuppressWarnings("unchecked")
public class Word implements Parcelable {

    private Word(Parcel source) {

        setOriginalWord(source.readString());

        setVariants(source.readArrayList(getSystemClassLoader()));
        setInvalidTranslations(source.readArrayList(getSystemClassLoader()));
    }

    public Word(String originalWord) {

        this.originalWord = originalWord;
        this.variants = new ArrayList<String>();
        this.invalidTranslations = new ArrayList<String>();
    }

    public Word() {
        this(EMPTY);
    }

    public List<String> getVariants() {
        return variants == null ? Collections.EMPTY_LIST : variants;
    }

    public void addVariant(String variant) throws BaseException {
        if (isNotBlank(variant)) {

            if (invalidTranslations.contains(variant)) {
                throw getWordCreationException(WORD_VARIANTS_ERROR, getContext(), variant);
            }

            if (!variants.contains(variant)) {
                variants.add(variant);
            }
        }
    }

    public void addInvalidVariant(String variant) throws BaseException {
        if (isNotBlank(variant)) {

            if (variants.contains(variant)) {
                throw getWordCreationException(WORD_INVALID_VARIANTS_ERROR, getContext(), variant);
            }

            if (!invalidTranslations.contains(variant)) {
                invalidTranslations.add(variant);
            }
        }
    }

    public void setVariants(List<String> variants) {
        if (variants == null) {
            this.variants.clear();
        } else {
            this.variants = variants;
        }
    }

    public String getOriginalWord() {
        return originalWord;
    }

    public void setOriginalWord(String originalWord) {
        this.originalWord = originalWord;
    }

    public List<String> getInvalidTranslations() {
        return invalidTranslations == null ? Collections.EMPTY_LIST : invalidTranslations;
    }

    public void setInvalidTranslations(List<String> invalidTranslations) {
        if (invalidTranslations == null) {
            this.invalidTranslations.clear();
        } else {
            this.invalidTranslations = invalidTranslations;
        }
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(getOriginalWord());
        dest.writeList(getVariants());
        dest.writeList(getInvalidTranslations());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Word word = (Word) o;

        if (originalWord != null ? !originalWord.equals(word.originalWord) : word.originalWord != null) return false;
        if (!equalsTranslations(invalidTranslations, word.getInvalidTranslations())) return false;
        if (!equalsTranslations(variants, word.getVariants())) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = originalWord != null ? originalWord.hashCode() : 0;
        result = 31 * result + listHash(variants);
        result = 31 * result + listHash(invalidTranslations);
        return result;
    }

    private int listHash(List<String> list) {
        if (list == null) {
            return 0;
        }

        int result = 0;
        for (String s : list) {
            result += s.hashCode();
        }

        return result;
    }

    private boolean equalsTranslations(List<String> t1, List<String> t2) {

        if (t1 == null && t2 == null) {
            return true;
        } else {
            if (t1 == null || t2 == null) {
                return false;
            }
        }

        if (t1.isEmpty() && t2.isEmpty()) {
            return true;
        }

        return t1.size() == t2.size() && new HashSet<String>(t1).equals(new HashSet<String>(t2));
    }

    @SuppressWarnings("unused")
    public static final Parcelable.Creator<Word> CREATOR = new Parcelable.Creator<Word>() {

        @Override
        public Word createFromParcel(Parcel source) {
            return new Word(source);
        }

        @Override
        public Word[] newArray(int size) {
            return new Word[size];
        }
    };

    private String originalWord;
    private List<String> variants;
    private List<String> invalidTranslations;
}